package dm.ast.model.gen;

import com.sun.org.apache.bcel.internal.generic.NEW;
import dm.ast.*;
import dm.ast.model.gen.factory.BaseModelFactory;
import dm.ast.model.gen.factory.BoolExpModelFactory;
import dm.ast.model.gen.factory.ComplexityModel;
import dm.ast.model.gen.factory.FactoryConstant;
import test.utility.Randomly;

import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class BoolExpressionGen extends ASTGenBase{

    //用于生成表达式
    ExpressionGen expGen;

    public BoolExpressionGen() {
    }

    public BoolExpressionGen(boolean[] boolexpTypesFlags) {
        this.testFlags = boolexpTypesFlags;
        expGen = new ExpressionGen();
        expGen.setTestFlags(boolexpTypesFlags);
    }

    //随机生成bool表达式类型
    public DmBoolExpType getRanDmBoolExpType(int dep_t){
        DmBoolExpType boolType;
        List<DmBoolExpType> validOptions = new ArrayList<>(Arrays.asList(DmBoolExpType.values()));
        if(dep_t < 2){  //因为exists谓词的最小深度为2
            validOptions.remove(DmBoolExpType.EXISTS_OP);
        }
        if(!testFlags[BaseModelFactory.INDEX_NULL]){
            validOptions.remove(DmBoolExpType.NULL_OP);
        }
        if(!testFlags[BaseModelFactory.INDEX_BETWEEN]){
            validOptions.remove(DmBoolExpType.BETWEEN_OP);
        }
        if(!testFlags[BaseModelFactory.INDEX_IN]){
            validOptions.remove(DmBoolExpType.IN_OP);
        }
        if(!testFlags[BaseModelFactory.INDEX_LIKE]){
            validOptions.remove(DmBoolExpType.LIKE_OP);
        }
        if(!testFlags[BaseModelFactory.INDEX_EXISTS]){
            validOptions.remove(DmBoolExpType.EXISTS_OP);
        }
        boolType = Randomly.fromList(validOptions);

        return boolType;
    }


    @Override
    public DmASTNode gen(int astLevel , int wid_t , int dep_t){
        ComplexityModel model = BoolExpModelFactory.boolModels(wid_t , dep_t);
        DmBoolExpression boolExp = singleGen(astLevel , model.comps[0].wid_t , model.comps[0].dep_t);
        if(wid_t < 0){
            System.out.println(String.format("w:%d , d:%d" , wid_t , dep_t));
            throw new AssertionError();
        }

        int i = 1;
        int tmp_wid_use = 0;
        int tmp_wid = 0;
        int tmp_dep = 0;
        while(i < model.count){
            DmBoolOperator op = OperatorGen.boolOperatorRandom();
            tmp_wid = model.comps[i].wid_t;
            if(tmp_wid == 0){  //中间宽度为0 ， 那么后续的宽度也为0，不必考虑
                break;
            }
            //如果多次添加了一元操作符
            //那么适当减少该部分的宽度
            tmp_wid = tmp_wid  - tmp_wid_use;
            tmp_dep = model.comps[i].dep_t;
            if(op.getExpNum() == 1){
                tmp_wid_use++;
                //如果该部分的宽度大于2，那么加上次一元操作符
                //否则，舍弃该一元操作符，同时，如果该部分的dep_t =1 ,那么舍弃model的这一部分
                if(tmp_wid > 2){
                    boolExp = DmBoolExpression.buildBoolExp(boolExp , op);
                }else {
                    if(tmp_dep == 1){  //目标宽度小于3，且dep_t = 1，那么舍弃Model的这一部分
                        i++;
                    }
                }
            }else {
                tmp_wid_use = 0;
                boolExp = DmBoolExpression.buildBoolExp(boolExp , singleGen(astLevel , tmp_wid , tmp_dep) , op);
                i++;
            }
        }
        return boolExp;
    }

    //单一bool表达式
    //例如logic表达式，In表达式，between表达式
    // 1 > 1 or 1 = 1。这种bool表达式是复合表达式，因为它有两个单独的bool表达式组成，不在此考虑范围内
    public DmBoolExpression singleGen(int astLevel , int wid_t , int dep_t){
        //todo , 需要重写
        //？如果dep_t = 1 ，进入一般bool表达式生成
        //？如果dep_t > 1,进入复杂bool表达式生成
        //1、逻辑比较表达式
        //2、In表达式
        //3、between表达式
        //4、exists表达式
        //5、like表达式
        // ..
        DmBoolExpression boolExp;
        DmBoolExpType boolType = getRanDmBoolExpType(dep_t);
        if(dep_t < 0){
            throw new AssertionError(boolType);
        }
        switch (boolType){
            case LOGIC:
                boolExp = logicBoolGen(astLevel , wid_t , dep_t);
                break;
            case IN_OP:
                boolExp = inBoolGen(astLevel , wid_t , dep_t);
                break;
            case BETWEEN_OP:
                boolExp = betweenBoolGen(astLevel , wid_t , dep_t);
                break;
            case NULL_OP:
                boolExp = defBoolGen(astLevel , wid_t , dep_t , OperatorGen.nullOperatorRandom());  //todo 有问题
                break;
            case LIKE_OP:
                boolExp = likeBoolGen(astLevel , wid_t , dep_t);
                break;
            case EXISTS_OP:
                boolExp = existsBoolGen(astLevel , wid_t , dep_t);
                break;
            default:
                throw new AssertionError(boolType);
        }
        return boolExp;
    }

    //一般bool表达式
    public DmBoolExpression defBoolGen(int astLevel , int wid_t , int dep_t , DmOperator op){
        DmBoolExpression boolExp = new DmBoolExpression();
        boolExp.setTargetWidt(wid_t);
        boolExp.setTargetDept(dep_t);
        boolExp.setASTLevel(astLevel);

        DmExpression leftExp = null;
        DmExpression rightExp = null;
        int expNum = op.getExpNum();

        ComplexityModel model = BoolExpModelFactory.defaultModel(wid_t - 1 , dep_t , expNum);
        boolExp.setOperator(op);
        DmDataType rType = Randomly.fromList(ExpressionGen.supportedExpRetType());
        leftExp = (DmExpression) expGen.gen(astLevel , model.comps[0].wid_t , model.comps[0].dep_t , rType);
        boolExp.setLeftExp(leftExp);
        if(expNum != 1){
            rightExp = (DmExpression) expGen.gen(astLevel , model.comps[1].wid_t , model.comps[1].dep_t , rType);
            boolExp.setRightExp(rightExp);
        }
        return boolExp;

    }


    //logic表达式
    public DmBoolExpression logicBoolGen(int astLevel , int wid_t , int dep_t){
        DmBoolExpression logicBoolExp;
        DmOperator op = OperatorGen.logicOperatorRandom();
        if(wid_t < 3){
            wid_t = 3;
        }
        //小概率生成rownum表达式
        if(testFlags[BaseModelFactory.INDEX_ROWNUM] && Randomly.getBooleanWithRatherLowProbability()){
            logicBoolExp = new DmRownumExpression();
            logicBoolExp.setTargetWidt(wid_t);
            logicBoolExp.setTargetDept(dep_t);
            logicBoolExp.setASTLevel(astLevel);
            logicBoolExp.setRightExp((DmExpression) expGen.gen(astLevel , wid_t ,dep_t , DmDataType.INT));
        }else {  //生成普通logic表达式
            logicBoolExp = new DmBoolExpression();
            logicBoolExp.setTargetWidt(wid_t);
            logicBoolExp.setTargetDept(dep_t);
            logicBoolExp.setASTLevel(astLevel);
            ComplexityModel model = BoolExpModelFactory.logicModels(wid_t , dep_t);
            DmDataType rType = Randomly.fromList(ExpressionGen.supportedExpRetType());
            DmExpression leftExp = (DmExpression) expGen.gen(astLevel , model.comps[0].wid_t , model.comps[0].dep_t , rType);
            DmExpression rightExp = (DmExpression) expGen.gen(astLevel , model.comps[1].wid_t , model.comps[1].dep_t , rType);
            logicBoolExp.setLeftExp(leftExp);
            logicBoolExp.setRightExp(rightExp);

            //此处定量比较，增加all 、 some 、any关键字
            // c1 > all(subquery)
            if(model.comps[0].dep_t == 1 && model.comps[1].dep_t > 1){
                if(testFlags[BaseModelFactory.INDEX_LOGIC_ALL]){
                    ArrayList<Integer> status = new ArrayList<>();
                    status.add(0);
                    status.add(1);
                    status.add(2);
                    status.add(3);
                    logicBoolExp.setAllOrSomeOrAny(Randomly.fromList(status));
                }
            }
        }
        logicBoolExp.setOperator(op);
        return logicBoolExp;
    }

    //in表达式
    public DmBoolExpression inBoolGen(int astLevel , int wid_t , int dep_t){
        List<DmExpression> expRight = null;  //右操作数
        DmInExpression inExp = new DmInExpression();
        int use_widt = wid_t;
        if(use_widt < 2){
            use_widt = 2;
        }
        inExp.setTargetWidt(use_widt);
        inExp.setTargetDept(dep_t);
        inExp.setASTLevel(astLevel);
        ComplexityModel models = BoolExpModelFactory.inModels(use_widt , dep_t);
        if(models.count < 2){
            throw new AssertionError("inModel Error");
        }
        DmDataType rType = Randomly.fromList(ExpressionGen.supportedExpRetType());
        //in的左边表达式的个数
        int t = models.getInLeft();
        //左边划分
        for (int i = 0; i < t; i++) {

            DmExpression leftExp = (DmExpression) expGen.gen(astLevel , models.comps[i].wid_t , models.comps[i].dep_t , rType);
            inExp.addInLeftExp(leftExp);
        }
        //右边划分
        expRight = new ArrayList<DmExpression>();
        for (int i = 0; i < models.count; i++) {
            DmExpression rightExp = (DmExpression) expGen.gen(astLevel , models.comps[i].wid_t , models.comps[i].dep_t , rType);
            expRight.add(rightExp);
            if(expRight.size() == t){
                inExp.addInrigExp(expRight);
                expRight = new ArrayList<DmExpression>();
            }
        }
        inExp.setNotFlag(Randomly.getBoolean());
        return inExp;
    }

    //between表达式
    public DmBoolExpression betweenBoolGen(int astLevel , int wid_t , int dep_t){
        DmBetweenExpression betweenExp = new DmBetweenExpression();
        int use_widt = wid_t;
        if(use_widt < 3){
            use_widt = 3;
        }
        betweenExp.setTargetWidt(use_widt);
        betweenExp.setTargetDept(dep_t);
        betweenExp.setASTLevel(astLevel);

        ComplexityModel model = BoolExpModelFactory.betweenModels(use_widt , dep_t);
        DmDataType rType = Randomly.fromList(ExpressionGen.supportedExpRetType());
        DmExpression leftExp = (DmExpression) expGen.gen(astLevel , model.comps[0].wid_t , model.comps[0].dep_t , rType);
        DmExpression minExp = (DmExpression) expGen.gen(astLevel , model.comps[1].wid_t , model.comps[1].dep_t , rType);
        DmExpression maxExp = (DmExpression) expGen.gen(astLevel , model.comps[2].wid_t , model.comps[2].dep_t , rType);
        betweenExp.setExps(leftExp , minExp , maxExp);
        betweenExp.setNotFlag(Randomly.getBoolean());

        return betweenExp;
    }

    //like表达式
    public DmLikeExpression likeBoolGen(int astLevel , int wid_t , int dep_t){
        DmLikeExpression likeExp = new DmLikeExpression();
        int use_widt = wid_t;
        if(use_widt < 3){
            use_widt = 3;
        }
        likeExp.setTargetWidt(use_widt);
        likeExp.setTargetDept(dep_t);
        likeExp.setASTLevel(astLevel);

        likeExp.setRowFlag(Randomly.getBoolean());
        if(use_widt > 3){
            likeExp.setEscapeFlag(Randomly.getBoolean());
        }

        DmExpression leftExp = null;
        DmExpression rightExp = null;
        DmDataType rType = DmDataType.CHAR;
        int tmp_widt = use_widt;
        if(likeExp.getEscapeFlag()){
            tmp_widt -= 2;
            if(tmp_widt < 1){
                likeExp.setEscapeFlag(false);
                tmp_widt = 3;
            }
        }
        if(likeExp.getRowFlag()){
            rightExp = (DmExpression) expGen.gen(astLevel , tmp_widt , dep_t , rType);
            likeExp.setRightExp(rightExp);
        }else {
            ComplexityModel model = BoolExpModelFactory.logicModels(tmp_widt , dep_t);
            leftExp = (DmExpression) expGen.gen(astLevel , model.comps[0].wid_t , model.comps[0].dep_t , rType);
            rightExp = (DmExpression) expGen.gen(astLevel , model.comps[1].wid_t , model.comps[1].dep_t , rType);
            likeExp.setLeftExp(leftExp);
            likeExp.setRightExp(rightExp);
        }
        if(likeExp.getEscapeFlag()){
            likeExp.setEscapeChar(Randomly.fromOptions("*" , "#" , "@"));
        }
        return likeExp;
    }

    //exists表达式
    public DmExistsExpression existsBoolGen(int astLevel , int wid_t , int dep_t){
        DmExistsExpression existsExp = new DmExistsExpression();

        SelectGen selGen = new SelectGen();
        int tmp_wid = wid_t - 2;
        if (tmp_wid < 2) {
            tmp_wid = FactoryConstant.MIN_WIDT_COMP;
        }
        DmSelect s = (DmSelect) selGen.gen(astLevel + 1 , tmp_wid , dep_t - 1 , 1);
        s.setStarFlag(true);
        existsExp.setSubSelect(s);
        return existsExp;
    }

    //join bool类型
    public void JoinBoolGen(int astLevel,int wid_t,int dep_t,DmJoinExpression on){
        DmOperator op = OperatorGen.logicOperatorRandom();
        if(wid_t < 3){
            wid_t = 3;
        }

        //划分为几个单一的宽度为3的表达式
        int count = wid_t / 3;

        //生成单一的表达式
        DmSingleJoinExpression singleJoinExpression = new DmSingleJoinExpression();
        singleJoinExpression.setOperator(op);

        on.joinbool = new ArrayList<>();
        on.ops = new ArrayList<>();
        on.joinbool.add(singleJoinExpression);

        //构造on后边符合表达式
        for (int i = 0; i < count; i++) {
            DmSingleJoinExpression singleJoinExpression1 = new DmSingleJoinExpression();
            singleJoinExpression1.setOperator(op);

            //大概率产生一个AND操作符
            DmBoolOperator op2 = new DmBoolOperator();
            if(Randomly.getBooleanWithRatherLowProbability()){
                op2.setOperator("OR");
            }else {
                op2.setOperator("AND");
            }

            on.ops.add(op2);
            on.joinbool.add(singleJoinExpression1);
        }
    }

    //singjoinbool表达式 构造（+）类型的外连接时用到的
    public DmBoolExpression SingJoinGen(int astLevel,int wid_t,int dep_t){
        DmOperator op = new DmBoolOperator();
        op.setOperator("=");
        if(wid_t<3){
            wid_t = 3;
        }
        //生成单一的表达式
        DmSingleJoinExpression singleJoinExpression = new DmSingleJoinExpression();
        //确定（+）的左右
        if(Randomly.getBoolean()){
            singleJoinExpression.tag = 1;
        }else {
            singleJoinExpression.tag = 2;
        }
        singleJoinExpression.setOperator(op);
        return singleJoinExpression;
    }

}
